// ==================================================================================================
// Copyright(C) 2018 FI Ltd. All rights reserved.
//
// SYSTEM NAME	   : FI.Net Application Framework 
// COMPONENT ID	   : FI.Transactions.Transaction
// COMPONENT DESC  : Transaction class, wrap the database transaction and provide the similar interface with system transaction.
//
// CREATED DATE/BY : 18 Aug 2018 / Tian Mi
//
// REVISION HISTORY:	DATE/BY						SR#/CS/PM#/OTHERS		DESCRIPTION OF CHANGE
// ==================================================================================================



using FI.Core.Data;
using System.Data.Common;
namespace FI.Core.Transactions
{
    /// <summary>
    /// Controls to check whether there is ambient transaction and which type is: 
    /// is it System.Transactions or the transaction of FI?
    /// 
    /// It must be called as the order
    /// BeginTransaction
    /// Commit
    /// Rollback
    /// CloseConnection
    /// <example>
    /// <code>
    /// try
    /// {
    ///        trans = _transactionHelper.BeginTransaction(db);
    /// 
    ///         if (trans == null)
    ///           {
    ///             //It is system transaction
    ///              db.ExecuteNonQuery(command);
    ///           }
    ///           else
    ///          {
    ///               db.ExecuteNonQuery(command, trans);
    ///          }
    /// 
    ///         _transactionHelper.Commit(trans);
    ///     }
    ///     catch
    ///       {
    ///           _transactionHelper.Rollback(trans);
    ///          throw;
    ///      }
    ///      finally
    ///      {
    ///          _transactionHelper.CloseConnection();
    ///      }
    /// </code>
    /// </example>
    /// </summary>
    public class TransactionHelper
    {
        /// <summary>
        /// Gets or sets the connection.
        /// </summary>
        /// <value>The connection.</value>
        public DbConnection Connection { get; private set; }

        /// <summary>
        /// Gets or sets the database.
        /// </summary>
        /// <value>The database.</value>
        public string Database { get; private set; }

        #region Public Methods
        /// <summary>
        /// Closes the connection.
        /// </summary>
        public void CloseConnection()
        {
            if (IsSysOrIcTransaction())
            {
                return;
            }

            if (Connection != null)
            {
                Connection.Close();
            }
        }

        /// <summary>
        /// Rollbacks the specified transaction.
        /// </summary>
        /// <param name="transaction">The transaction.</param>
        public void Rollback(DbTransaction transaction)
        {
            if (IsSysOrIcTransaction())
            {
                return;
            }

            if (transaction == null)
            {
                return;
            }
            transaction.Rollback();
        }

        /// <summary>
        /// Commits the specified transaction.
        /// </summary>
        /// <param name="transaction">The transaction.</param>
        public void Commit(DbTransaction transaction)
        {
            if (IsSysOrIcTransaction())
            {
                return;
            }

            if (transaction==null)
            {
                return;   
            }
            //Commit the transaction created by us
            transaction.Commit();
        }

        /// <summary>
        /// Begins the transaction.
        /// </summary>
        /// <param name="databaseName">Name of the database.</param>
        /// <returns>The <see cref="DbTransaction"/>.</returns>
        public DbTransaction BeginTransaction(string databaseName)
        {
            Database = databaseName;

            DbTransaction transaction = null;
            DbConnection conn;

            //Check System Transaction
            if (System.Transactions.Transaction.Current != null)
            {
                return null;
            }

            //Check Iconnect Transaction
            transaction = GetIconnectTransaction();
            if (transaction != null)
            {
                return transaction;
            }

            //Create a Ado.net Transaction
            conn = DatabaseFactories.GetDatabase(databaseName).CreateConnection();
            conn.Open();
            transaction = conn.BeginTransaction();
            Connection = conn;

            return transaction;
        }

        #endregion

        #region Private Methods
        private DbTransaction GetIconnectTransaction()
        {
            return Transaction.GetDbTransaction(Database);
        }
        private bool IsSysOrIcTransaction()
        {
            //Check System Transaction
            if (System.Transactions.Transaction.Current != null)
            {
                return true;
            }
            //Check Iconnect Transaction
            return (GetIconnectTransaction() != null);
        }
        #endregion
    }
}